/*
 * Copyright (C) 2009 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.cooliris.media;

import java.util.Arrays;
import java.util.Comparator;
import java.util.HashMap;

import javax.microedition.khronos.opengles.GL10;
import javax.microedition.khronos.opengles.GL11;

import android.content.Context;
import android.opengl.GLSurfaceView;
import android.util.Log;

import com.cooliris.app.App;
import com.cooliris.app.Res;
import com.cooliris.utils.MyLog;

public final class GridDrawManager {
	public static final int PASS_THUMBNAIL_CONTENT = 0;
	public static final int PASS_FOCUS_CONTENT = 1;
	public static final int PASS_FRAME = 2;
	public static final int PASS_PLACEHOLDER = 3;
	public static final int PASS_FRAME_PLACEHOLDER = 4;
	public static final int PASS_TEXT_LABEL = 5;
	public static final int PASS_SELECTION_LABEL = 6;
	public static final int PASS_VIDEO_LABEL = 7;
	public static final int PASS_LOCATION_LABEL = 8;
	public static final int PASS_MEDIASET_SOURCE_LABEL = 9;

	private static final MediaItemTexture.Config sThumbnailConfig = new MediaItemTexture.Config();
	private final DisplayItem[] mDisplayItems;
	private final DisplaySlot[] mDisplaySlots;
	private final DisplayList mDisplayList;
	private final GridCamera mCamera;
	private final GridDrawables mDrawables;
	private IndexRange mBufferedVisibleRange;
	private IndexRange mVisibleRange;
	private int mSelectedSlot;
	private int mCurrentFocusSlot;
	private DisplayItem[] mItemsDrawn;
	private int mDrawnCounter;
	private float mTargetFocusMixRatio = 0.0f;
	private float mFocusMixRatio = 0.0f;
	private final FloatAnim mSelectedMixRatio = new FloatAnim(0f);
	private float mCurrentFocusItemWidth;
	private float mCurrentFocusItemHeight;
	private boolean mCurrentFocusIsPressed;
	private final Texture mNoItemsTexture;
	private int mCurrentScaleSlot;
	private float mSpreadValue;
	private ScaleGestureDetector mScaleGestureDetector;
	private boolean mHoldPosition;
	private static final String TAG = "GridDrawManager";
	private Context mContext;
	private static final Comparator<DisplayItem> sDisplayItemComparator = new Comparator<DisplayItem>() {
		public int compare(DisplayItem a, DisplayItem b) {
			if (a == null || b == null) {
				return 0;
			}
			float delta = (a.mAnimatedPosition.z - b.mAnimatedPosition.z);
			if (delta > 0) {
				return 1;
			} else if (delta < 0) {
				return -1;
			} else {
				return 0;
			}
		}
	};

	public GridDrawManager(Context context, GridCamera camera,
			GridDrawables drawables, DisplayList displayList,
			DisplayItem[] displayItems, DisplaySlot[] displaySlots) {
		sThumbnailConfig.thumbnailWidth = 128;
		sThumbnailConfig.thumbnailHeight = 96;
		this.mContext=context;
		mDisplayItems = displayItems;
		mDisplaySlots = displaySlots;
		mDisplayList = displayList;
		mDrawables = drawables;
		mCamera = camera;		
		mItemsDrawn = new DisplayItem[GridLayer.MAX_ITEMS_DRAWABLE];

		StringTexture.Config stc = new StringTexture.Config();
		// stc.bold = true;
		stc.fontSize = 14 * App.PIXEL_DENSITY;
		stc.sizeMode = StringTexture.Config.SIZE_EXACT;
		stc.overflowMode = StringTexture.Config.OVERFLOW_FADE;
		stc.xalignment = StringTexture.Config.ALIGN_HCENTER;
		Log.i(TAG, "GridDrawManager__constuctor");		
		mNoItemsTexture = new StringTexture(context.getResources().getString(
				Res.string.no_items), stc);

	}

	public void prepareDraw(IndexRange bufferedVisibleRange,
			IndexRange visibleRange, int selectedSlot, int currentFocusSlot,
			int currentScaleSlot, boolean currentFocusIsPressed,
			float spreadValue, ScaleGestureDetector scaleGestureDetector,
			boolean holdPosition) {
		mBufferedVisibleRange = bufferedVisibleRange;
		mVisibleRange = visibleRange;
		mSelectedSlot = selectedSlot;
		mCurrentFocusSlot = currentFocusSlot;
		mCurrentFocusIsPressed = currentFocusIsPressed;
		mCurrentScaleSlot = currentScaleSlot;
		mScaleGestureDetector = scaleGestureDetector;
		mSpreadValue = spreadValue;
		mHoldPosition = holdPosition;
	}

	public boolean update(float timeElapsed) {
		mFocusMixRatio = FloatUtils.animate(mFocusMixRatio,
				mTargetFocusMixRatio, timeElapsed);
		mTargetFocusMixRatio = 0.0f;
		if (mFocusMixRatio != mTargetFocusMixRatio
				|| mSelectedMixRatio.isAnimating()) {
			return true;
		}
		return false;
	}

	public void drawThumbnails(RenderView view, GL11 gl, int state) {
		final GridDrawables drawables = mDrawables;
		final DisplayList displayList = mDisplayList;
		final DisplayItem[] displayItems = mDisplayItems;
		final int firstBufferedVisibleSlot = mBufferedVisibleRange.begin;
		final int lastBufferedVisibleSlot = mBufferedVisibleRange.end;
		final int firstVisibleSlot = mVisibleRange.begin;
		final int lastVisibleSlot = mVisibleRange.end;
		final int selectedSlotIndex = mSelectedSlot;
		final int currentFocusSlot = mCurrentFocusSlot;
		final int currentScaleSlot = mCurrentScaleSlot;
		final DisplayItem[] itemsDrawn = mItemsDrawn;
		itemsDrawn[0] = null; // No items drawn yet.
		int drawnCounter = 0;
		final GridQuad grid = GridDrawables.sGrid;
		grid.bindArrays(gl);
		int numTexturesQueued = 0;
		Context context = view.getContext();
		for (int itrSlotIndex = firstBufferedVisibleSlot; itrSlotIndex <= lastBufferedVisibleSlot; ++itrSlotIndex) {
			int index = itrSlotIndex;
			boolean priority = !(index < firstVisibleSlot || index > lastVisibleSlot);
			int startSlotIndex = 0;
			final int maxDisplayedItemsPerSlot = (index == mCurrentScaleSlot) ? GridLayer.MAX_DISPLAYED_ITEMS_PER_FOCUSED_SLOT
					: GridLayer.MAX_DISPLAYED_ITEMS_PER_SLOT;
			if (index != mCurrentScaleSlot) {
				for (int j = maxDisplayedItemsPerSlot - 1; j >= 0; --j) {
					DisplayItem displayItem = displayItems[(index - firstBufferedVisibleSlot)
							* GridLayer.MAX_ITEMS_PER_SLOT + j];
					if (displayItem == null) {
						continue;
					} else {
						Texture texture = displayItem.getThumbnailImage(
								context, sThumbnailConfig);
						if (texture != null && texture.isLoaded() == false) {
							startSlotIndex = j;
							break;
						}
					}
				}
			}
			// Prime the textures in the reverse order.
			for (int j = 0; j < maxDisplayedItemsPerSlot; ++j) {
				int stackIndex = (index == mCurrentScaleSlot) ? maxDisplayedItemsPerSlot
						- j - 1
						: j;
				DisplayItem displayItem = displayItems[(index - firstBufferedVisibleSlot)
						* GridLayer.MAX_ITEMS_PER_SLOT + stackIndex];
				if (displayItem == null) {
					continue;
				} else {
					displayItem.mCurrentSlotIndex = index;
					if (selectedSlotIndex != Shared.INVALID
							&& (index <= selectedSlotIndex - 2 || index >= selectedSlotIndex + 2)) {
						displayItem.clearScreennailImage();
					}
					Texture texture = displayItem.getThumbnailImage(context,
							sThumbnailConfig);
					if (index == mCurrentScaleSlot && texture != null
							&& !texture.isLoaded()) {
						view.prime(texture, true);
						view.bind(texture);
					} else if (texture != null && !texture.isLoaded()
							&& numTexturesQueued <= 6) {
						boolean isCached = texture.isCached();
						view.prime(texture, priority);
						view.bind(texture);
						if (priority && isCached
								&& texture.mState != Texture.STATE_ERROR)
							++numTexturesQueued;
					}
				}
			}
			if (itrSlotIndex == selectedSlotIndex) {
				continue;
			}
			view.prime(drawables.mTexturePlaceholder, true);
			Texture placeholder = (state == GridLayer.STATE_GRID_VIEW||state==GridLayer.STATE_TIME_GRID) ? drawables.mTexturePlaceholder
					: null;
			final boolean pushDown = (state == GridLayer.STATE_GRID_VIEW || state == GridLayer.STATE_FULL_SCREEN) ? false
					: true;
			for (int j = 0; j < GridLayer.MAX_ITEMS_PER_SLOT; ++j) {
				DisplayItem displayItem = displayItems[(index - firstBufferedVisibleSlot)
						* GridLayer.MAX_ITEMS_PER_SLOT + j];
				if (displayItem == null)
					continue;
				Texture texture = displayItem.getThumbnailImage(context,
						sThumbnailConfig);
				if (texture == null || !texture.isLoaded()) {
					if (currentScaleSlot != index) {
						if (j == 0) {
							final MediaSet parentSet = displayItem.mItemRef.mParentMediaSet;
							if (parentSet != null
									&& parentSet.getNumItems() <= 1) {
								displayList.setAlive(displayItem, false);
							}
						} else {
							displayList.setAlive(displayItem, false);
						}
					}
				}
				final float dx1 = mScaleGestureDetector.getTopFingerDeltaX();
				final float dy1 = mScaleGestureDetector.getTopFingerDeltaY();
				final float dx2 = mScaleGestureDetector.getBottomFingerDeltaX();
				final float dy2 = mScaleGestureDetector.getBottomFingerDeltaY();
				final float span = mScaleGestureDetector.getCurrentSpan();
				if (state == GridLayer.STATE_FULL_SCREEN) {
					displayList.setOffset(displayItem, false, true, span, dx1,
							dy1, dx2, dy2);
				} else {
					if (!mHoldPosition) {
						if (state != GridLayer.STATE_GRID_VIEW) {
							if (currentScaleSlot == index) {
								displayList.setOffset(displayItem, true, false,
										span, dx1, dy1, dx2, dy2);
							} else if (currentScaleSlot != Shared.INVALID) {
								displayList.setOffset(displayItem, true, true,
										span, dx1, dy1, dx2, dy2);
							} else {
								displayList.setOffset(displayItem, false,
										false, span, dx1, dy1, dx2, dy2);
							}
						} else {
							float minVal = -1.0f;
							float maxVal = GridCamera.EYE_Z * 0.5f;
							float zVal = minVal + mSpreadValue;
							zVal = FloatUtils.clamp(zVal, minVal, maxVal);
							if (Float.isInfinite(zVal) || Float.isNaN(zVal)) {
								mCamera.moveZTo(0);
							} else {
								mCamera.moveZTo(-zVal);
							}
						}
					}
				}
			}
			for (int j = startSlotIndex; j < GridLayer.MAX_ITEMS_PER_SLOT; ++j) {
				DisplayItem displayItem = displayItems[(index - firstBufferedVisibleSlot)
						* GridLayer.MAX_ITEMS_PER_SLOT + j];
				if (displayItem == null) {
					break;
				} else {
					if (currentFocusSlot == index) {
						displayList.setHasFocus(displayItem, true, pushDown);
						mTargetFocusMixRatio = 1.0f;
					} else {
						displayList.setHasFocus(displayItem, false, pushDown);
					}
					if (j >= maxDisplayedItemsPerSlot)
						continue;
					Texture texture = displayItem.getThumbnailImage(view
							.getContext(), sThumbnailConfig);
					if (texture != null) {
						if (index == mCurrentScaleSlot)
							displayItem.mAlive = true;
						if ((!displayItem.isAnimating() || !texture.isLoaded())
								&& displayItem.getStackIndex() > GridLayer.MAX_ITEMS_PER_SLOT) {
							displayList.setAlive(displayItem, true);
							continue;
						}
						if (index < firstVisibleSlot || index > lastVisibleSlot) {
							if (view.bind(texture)) {
								displayList.setAlive(displayItem, true);
							}
							continue;
						}
						drawDisplayItem(view, gl, displayItem, texture,
								PASS_THUMBNAIL_CONTENT, placeholder,
								displayItem.mAnimatedPlaceholderFade);
					} else {
						// Move on to the next stack.
						break;
					}
					if (drawnCounter >= GridLayer.MAX_ITEMS_DRAWABLE - 1
							|| drawnCounter < 0) {
						break;
					}
					// Insert in order of z.
					itemsDrawn[drawnCounter++] = displayItem;
					itemsDrawn[drawnCounter] = null;
				}
			}
		}
		mDrawnCounter = drawnCounter;
		grid.unbindArrays(gl);
	}

	public float getFocusQuadWidth() {
		return mCurrentFocusItemWidth;
	}

	public float getFocusQuadHeight() {
		return mCurrentFocusItemHeight;
	}

	public void drawFocusItems(RenderView view, GL11 gl, float zoomValue,
			boolean slideshowMode, float timeElapsedSinceView) {//用于放大与缩小
		int selectedSlotIndex = mSelectedSlot;
		GridDrawables drawables = mDrawables;
		GridCamera camera = mCamera;
		DisplayItem[] displayItems = mDisplayItems;
		int firstBufferedVisibleSlot = mBufferedVisibleRange.begin;
		int lastBufferedVisibleSlot = mBufferedVisibleRange.end;
		boolean isCameraZAnimating = mCamera.isZAnimating();
		for (int i = firstBufferedVisibleSlot; i <= lastBufferedVisibleSlot; ++i) {
			if (selectedSlotIndex != Shared.INVALID
					&& (i >= selectedSlotIndex - 2 && i <= selectedSlotIndex + 2)) {
				continue;
			}
			DisplayItem displayItem = displayItems[(i - firstBufferedVisibleSlot)
					* GridLayer.MAX_ITEMS_PER_SLOT];
			if (displayItem != null) {
				displayItem.clearScreennailImage();
			}
		}
		if (selectedSlotIndex != Shared.INVALID) {
			float camX = camera.mLookAtX * camera.mScale;
			int centerIndexInDrawnArray = (selectedSlotIndex - firstBufferedVisibleSlot)
					* GridLayer.MAX_ITEMS_PER_SLOT;
			if (centerIndexInDrawnArray < 0
					|| centerIndexInDrawnArray >= displayItems.length) {
				return;
			}
			DisplayItem centerDisplayItem = displayItems[centerIndexInDrawnArray];
			if (centerDisplayItem == null
					|| centerDisplayItem.mItemRef.mId == Shared.INVALID) {
				return;
			}
			boolean focusItemTextureLoaded = false;
			Texture centerTexture = centerDisplayItem.getScreennailImage(view
					.getContext());
			if (centerTexture != null && centerTexture.isLoaded()) {
				focusItemTextureLoaded = true;
			}
			float centerTranslateX = centerDisplayItem.mAnimatedPosition.x;
			final boolean skipPrevious = centerTranslateX < camX;
			view.setAlpha(1.0f);
			gl.glEnable(GL11.GL_BLEND);
			gl.glBlendFunc(GL11.GL_ONE, GL11.GL_ONE);
			float backupImageTheta = 0.0f;
			for (int i = -1; i <= 1; ++i) {
				if (slideshowMode && timeElapsedSinceView > 1.0f && i != 0)
					continue;
				float viewAspect = camera.mAspectRatio;
				int selectedSlotToUse = selectedSlotIndex + i;
				if (selectedSlotToUse >= 0
						&& selectedSlotToUse <= lastBufferedVisibleSlot) {
					int indexInDrawnArray = (selectedSlotToUse - firstBufferedVisibleSlot)
							* GridLayer.MAX_ITEMS_PER_SLOT;
					if (indexInDrawnArray < 0
							|| indexInDrawnArray >= displayItems.length) {
						return;
					}
					DisplayItem displayItem = displayItems[indexInDrawnArray];
					MediaItem item = displayItem.mItemRef;
					final Texture thumbnailTexture = displayItem
							.getThumbnailImage(view.getContext(),
									sThumbnailConfig);
					Texture texture = displayItem.getScreennailImage(view
							.getContext());
					if (isCameraZAnimating
							&& (texture == null || !texture.isLoaded())) {
						texture = thumbnailTexture;
						mSelectedMixRatio.setValue(0f);
						mSelectedMixRatio.animateValue(1f, 0.75f, view
								.getFrameTime());
					}
					Texture hiRes = (zoomValue != 1.0f && i == 0 && item
							.getMediaType() != MediaItem.MEDIA_TYPE_VIDEO) ? displayItem
							.getHiResImage(view.getContext())
							: null;
					if (App.PIXEL_DENSITY > 1.0f) {
						hiRes = texture;
					}
					if (i != 0) {
						displayItem.clearHiResImage();
					}
					if (hiRes != null) {
						if (!hiRes.isLoaded()) {
							view.bind(hiRes);
							view.prime(hiRes, true);
						} else {
							texture = hiRes;
						}
					}
					final Texture fsTexture = texture;
					if (texture == null || !texture.isLoaded()) {
						if (Math.abs(centerTranslateX - camX) < 0.1f) {
							if (focusItemTextureLoaded && i != 0) {
								view.bind(texture);
							}
							if (i == 0) {
								view.bind(texture);
								view.prime(texture, true);
							}
						}
						texture = thumbnailTexture;
						if (i == 0) {
							mSelectedMixRatio.setValue(0f);
							mSelectedMixRatio.animateValue(1f, 0.75f, view
									.getFrameTime());
						}
					}
					if (mCamera.isAnimating() || slideshowMode) {
						if (!slideshowMode && skipPrevious && i == -1) {
							continue;
						}
						if (!skipPrevious && i == 1) {
							continue;
						}
					}
					int theta = (int) displayItem.getImageTheta();
					// If it is in slideshow mode, we draw the previous item in
					// the next item's position.
					if (slideshowMode && timeElapsedSinceView < 1.0f
							&& timeElapsedSinceView != 0) {
						if (i == -1) {
							int nextSlotToUse = selectedSlotToUse + 1;
							if (nextSlotToUse >= 0
									&& nextSlotToUse <= lastBufferedVisibleSlot) {
								int nextIndexInDrawnArray = (nextSlotToUse - firstBufferedVisibleSlot)
										* GridLayer.MAX_ITEMS_PER_SLOT;
								if (nextIndexInDrawnArray >= 0
										&& nextIndexInDrawnArray < displayItems.length) {
									float currentImageTheta = displayItem.mAnimatedImageTheta;
									displayItem = displayItems[nextIndexInDrawnArray];
									backupImageTheta = displayItem.mAnimatedImageTheta;
									displayItem.mAnimatedImageTheta = currentImageTheta;
									view.setAlpha(1.0f - timeElapsedSinceView);
								}
							}
						} else if (i == 0) {
							displayItem.mAnimatedImageTheta = backupImageTheta;
							view.setAlpha(timeElapsedSinceView);
						}
					}
					if (texture != null) {
						int vboIndex = i + 1;
						float alpha = view.getAlpha();
						float selectedMixRatio = mSelectedMixRatio
								.getValue(view.getFrameTime());
						if (selectedMixRatio != 1f) {
							texture = thumbnailTexture;
							view.setAlpha(alpha * (1.0f - selectedMixRatio));
						}
						GridQuad quad = GridDrawables.sFullscreenGrid[vboIndex];
						float u = texture.getNormalizedWidth();
						float v = texture.getNormalizedHeight();
						float imageWidth = texture.getWidth();
						float imageHeight = texture.getHeight();
						boolean portrait = ((theta / 90) % 2 == 1);
						if (portrait) {
							viewAspect = 1.0f / viewAspect;
						}
						quad.resizeQuad(viewAspect, u, v, imageWidth,
								imageHeight);
						quad.bindArrays(gl);
						drawDisplayItem(view, gl, displayItem, texture,
								PASS_FOCUS_CONTENT, null, 0.0f);
						quad.unbindArrays(gl);
						if (selectedMixRatio != 0.0f
								&& selectedMixRatio != 1.0f) {
							texture = fsTexture;
							if (texture != null) {
								float drawAlpha = selectedMixRatio;
								view.setAlpha(alpha * drawAlpha);
								u = texture.getNormalizedWidth();
								v = texture.getNormalizedHeight();
								imageWidth = texture.getWidth();
								imageHeight = texture.getHeight();
								quad.resizeQuad(viewAspect, u, v, imageWidth,
										imageHeight);
								quad.bindArrays(gl);
								drawDisplayItem(view, gl, displayItem,
										fsTexture, PASS_FOCUS_CONTENT, null,
										1.0f);
								quad.unbindArrays(gl);
							}
						}
						if (i == 0 || slideshowMode) {
							mCurrentFocusItemWidth = quad.getWidth();
							mCurrentFocusItemHeight = quad.getHeight();
							if (portrait) {
								// Swap these values.
								float itemWidth = mCurrentFocusItemWidth;
								mCurrentFocusItemWidth = mCurrentFocusItemHeight;
								mCurrentFocusItemHeight = itemWidth;
							}
						}
						view.setAlpha(alpha);
						if (item.getMediaType() == MediaItem.MEDIA_TYPE_VIDEO) {
							// The play graphic overlay.
							GridDrawables.sVideoGrid.bindArrays(gl);
							drawDisplayItem(view, gl, displayItem,
									drawables.mTextureVideo, PASS_VIDEO_LABEL,
									null, 0);
							GridDrawables.sVideoGrid.unbindArrays(gl);
						}
					}
				}
			}
		}
	}

	public void drawBlendedComponents(RenderView view, GL11 gl, float alpha,
			int state, int hudMode, float stackMixRatio, float gridMixRatio,
			MediaBucketList selectedBucketList,
			MediaBucketList markedBucketList, boolean isFeedLoading) {
		int firstBufferedVisibleSlot = mBufferedVisibleRange.begin;
		int lastBufferedVisibleSlot = mBufferedVisibleRange.end;
		int firstVisibleSlot = mVisibleRange.begin;
		int lastVisibleSlot = mVisibleRange.end;
		DisplayItem[] displayItems = mDisplayItems;
		GridDrawables drawables = mDrawables;

		// We draw the frames around the drawn items.
		boolean currentFocusIsPressed = mCurrentFocusIsPressed;
		if (state != GridLayer.STATE_FULL_SCREEN) {
			GridDrawables.sFrame.bindArrays(gl);
			Texture texturePlaceHolder = (state == GridLayer.STATE_GRID_VIEW||state==GridLayer.STATE_TIME_GRID) ? drawables.mTextureGridFrame
					: drawables.mTextureFrame;
			for (int i = firstBufferedVisibleSlot; i <= lastBufferedVisibleSlot; ++i) {
				if (i < firstVisibleSlot || i > lastVisibleSlot) {
					continue;
				}
				boolean slotIsAlive = false;
				final int maxDisplayedItemsPerSlot = (i == mCurrentScaleSlot) ? GridLayer.MAX_DISPLAYED_ITEMS_PER_FOCUSED_SLOT
						: GridLayer.MAX_DISPLAYED_ITEMS_PER_SLOT;
				if (state != GridLayer.STATE_MEDIA_SETS
						&& state != GridLayer.STATE_TIMELINE) {
					for (int j = 0; j < maxDisplayedItemsPerSlot; ++j) {
						DisplayItem displayItem = displayItems[(i - firstBufferedVisibleSlot)
								* GridLayer.MAX_ITEMS_PER_SLOT + j];
						if (displayItem != null) {
							slotIsAlive |= displayItem.mAlive;
						}
					}
					if (!slotIsAlive) {
						DisplayItem displayItem = displayItems[(i - firstBufferedVisibleSlot)
								* GridLayer.MAX_ITEMS_PER_SLOT];
						if (displayItem != null) {					
							drawDisplayItem(view, gl, displayItem,
									texturePlaceHolder, PASS_FRAME_PLACEHOLDER,
									null, 0);
						}
					}
				}
			}
			Texture texturePressed = drawables.mTextureFramePressed;
			Texture textureFocus = drawables.mTextureFrameFocus;
			Texture textureGrid = drawables.mTextureGridFrame;
			Texture texture = drawables.mTextureFrame;

			boolean hasItems = false;

			int drawnCounter = mDrawnCounter;
			DisplayItem[] itemsDrawn = mItemsDrawn;
			if (texture != null) {
				if (drawnCounter > 0) {
					Arrays.sort(itemsDrawn, 0, drawnCounter,
							sDisplayItemComparator);
					float timeElapsedSinceGridView = gridMixRatio;
					float timeElapsedSinceStackView = stackMixRatio;
					for (int i = drawnCounter - 1; i >= 0; --i) {
						DisplayItem itemDrawn = itemsDrawn[i];
						if (itemDrawn == null) {
							continue;
						}
						boolean displayItemPresentInSelectedItems = selectedBucketList
								.find(itemDrawn.mItemRef);
						boolean displayItemPresentInMarkedItems = markedBucketList
								.find(itemDrawn.mItemRef);
						Texture previousTexture = (displayItemPresentInSelectedItems) ? texturePressed
								: texture;
						Texture textureToUse = (itemDrawn.getHasFocus()) ? (currentFocusIsPressed ? texturePressed
								: textureFocus)
								: ((displayItemPresentInSelectedItems) ? texturePressed
										: (displayItemPresentInMarkedItems) ? texture
												: textureGrid);
						float ratio = timeElapsedSinceGridView;
						if (itemDrawn.mAlive) {
							if (state != GridLayer.STATE_GRID_VIEW) {
								previousTexture = (displayItemPresentInSelectedItems) ? texturePressed
										: texture;
								textureToUse = (itemDrawn.getHasFocus()) ? (currentFocusIsPressed ? texturePressed
										: textureFocus)
										: previousTexture;
								if (timeElapsedSinceStackView == 1.0f) {
									ratio = mFocusMixRatio;
								} else {
									ratio = timeElapsedSinceStackView;
									previousTexture = textureGrid;
								}
							}
							hasItems = true;
							drawDisplayItem(view, gl, itemDrawn, textureToUse,
									PASS_FRAME, previousTexture, ratio);
						}
					}
				}
			}
			GridDrawables.sFrame.unbindArrays(gl);
			if (mSpreadValue <= 1.0f)
				gl.glDepthFunc(GL10.GL_ALWAYS);
			if (state == GridLayer.STATE_MEDIA_SETS
					|| state == GridLayer.STATE_TIMELINE) {
				DisplaySlot[] displaySlots = mDisplaySlots;
				GridDrawables.sTextGrid.bindArrays(gl);
				final float textOffsetY = 0.82f;
				gl.glTranslatef(0.0f, -textOffsetY, 0.0f);
				HashMap<String, StringTexture> stringTextureTable = GridDrawables.sStringTextureTable;
				ReverseGeocoder reverseGeocoder = App.get(view.getContext())
						.getReverseGeocoder();

				boolean itemsPresent = false;

				for (int i = firstBufferedVisibleSlot; i <= lastBufferedVisibleSlot; ++i) {
					itemsPresent = true;
					if (mSpreadValue > 1.0f)
						continue;
					DisplayItem displayItem = displayItems[(i - firstBufferedVisibleSlot)
							* GridLayer.MAX_ITEMS_PER_SLOT];
					if (displayItem != null) {
						DisplaySlot displaySlot = displaySlots[i
								- firstBufferedVisibleSlot];
						Texture textureString = displaySlot
								.getTitleImage(stringTextureTable);
						view.loadTexture(textureString);
						if (textureString != null) {
							if (i < firstVisibleSlot || i > lastVisibleSlot) {
								continue;
							}						
							hasItems = true;//add by ydy					
							drawDisplayItem(view, gl, displayItem,
									textureString, PASS_TEXT_LABEL, null, 0);
						}
					}
				}

				if ((!itemsPresent && !isFeedLoading) || (App.get(mContext).getPickIntent() && !hasItems && state == GridLayer.STATE_MEDIA_SETS && !isFeedLoading)) {
					// Draw the no items texture.
					int wWidth = view.getWidth();
					int wHeight = view.getHeight();				
					mNoItemsTexture.mWidth = wWidth - 280;	// modify by ydy
					int x = (int) Math.floor((wWidth / 2)
							- (mNoItemsTexture.getWidth() / 2));
					int y = (int) Math.floor((wHeight / 2)
							- (mNoItemsTexture.getHeight() / 2));				
					view.draw2D(mNoItemsTexture, x, y);

				}

				float yLocOffset = 0.2f;
				gl.glTranslatef(0.0f, -yLocOffset, 0.0f);
				for (int i = firstBufferedVisibleSlot; i <= lastBufferedVisibleSlot; ++i) {
					if (mSpreadValue > 1.0f)
						continue;
					DisplayItem displayItem = displayItems[(i - firstBufferedVisibleSlot)
							* GridLayer.MAX_ITEMS_PER_SLOT];
					if (displayItem != null) {
						DisplaySlot displaySlot = displaySlots[i
								- firstBufferedVisibleSlot];
						StringTexture textureString = displaySlot
								.getLocationImage(reverseGeocoder,
										stringTextureTable);
						if (textureString != null) {
							view.loadTexture(textureString);
							drawDisplayItem(view, gl, displayItem,
									textureString, PASS_TEXT_LABEL, null, 0);
						}
					}
				}
				if (state == GridLayer.STATE_TIMELINE) {
					GridDrawables.sLocationGrid.bindArrays(gl);
					Texture locationTexture = drawables.mTextureLocation;
					final float yLocationLabelOffset = 0.19f;
					for (int i = firstBufferedVisibleSlot; i <= lastBufferedVisibleSlot; ++i) {
						if (mCurrentScaleSlot != Shared.INVALID)
							continue;
						DisplayItem displayItem = displayItems[(i - firstBufferedVisibleSlot)
								* GridLayer.MAX_ITEMS_PER_SLOT];
						if (displayItem != null) {
							if (displayItem.mAlive == true) {
								DisplaySlot displaySlot = displaySlots[i
										- firstBufferedVisibleSlot];
								if (displaySlot.hasValidLocation()) {
									StringTexture textureString = displaySlot
											.getLocationImage(reverseGeocoder,
													stringTextureTable);
									float textWidth = (textureString != null) ? textureString
											.computeTextWidth()
											: 0;
									textWidth *= (mCamera.mOneByScale * 0.5f);
									if (textWidth == 0.0f) {
										textWidth -= 0.18f;
									}
									textWidth += 0.1f;
									gl.glTranslatef(textWidth,
											-yLocationLabelOffset, 0.0f);
									drawDisplayItem(view, gl, displayItem,
											locationTexture,
											PASS_LOCATION_LABEL, null, 0);
									gl.glTranslatef(-textWidth,
											yLocationLabelOffset, 0.0f);
								}
							}
						}
					}

					GridDrawables.sLocationGrid.unbindArrays(gl);
				} else if (state == GridLayer.STATE_MEDIA_SETS
						&& stackMixRatio > 0.0f) {
					GridDrawables.sSourceIconGrid.bindArrays(gl);
					Texture transparentTexture = drawables.mTextureTransparent;
					for (int i = firstBufferedVisibleSlot; i <= lastBufferedVisibleSlot; ++i) {
						DisplayItem displayItem = displayItems[(i - firstBufferedVisibleSlot)
								* GridLayer.MAX_ITEMS_PER_SLOT];
						if (mCurrentScaleSlot != Shared.INVALID)
							continue;
						if (displayItem != null) {
							if (displayItem.mAlive == true) {
								DisplaySlot displaySlot = displaySlots[i
										- firstBufferedVisibleSlot];
								Texture locationTexture = view.getResource(
										drawables.getIconForSet(displaySlot
												.getMediaSet(), false), false);

								// Draw the icon at 0.85 alpha over the top item
								// in the stack.
								gl.glTranslatef(0.24f, 0.5f, 0);
								drawDisplayItem(view, gl, displayItem,
										locationTexture,
										PASS_MEDIASET_SOURCE_LABEL,
										transparentTexture, 0.85f);
								gl.glTranslatef(-0.24f, -0.5f, 0);
							}
						}
					}
					GridDrawables.sSourceIconGrid.unbindArrays(gl);
				}
				gl.glTranslatef(0.0f, yLocOffset, 0.0f);
				gl.glTranslatef(0.0f, textOffsetY, 0.0f);
				GridDrawables.sTextGrid.unbindArrays(gl);
			}
			if (hudMode == HudLayer.MODE_SELECT
					&& state != GridLayer.STATE_FULL_SCREEN) {
				Texture textureSelectedOn = drawables.mTextureCheckmarkOn;
				Texture textureSelectedOff = drawables.mTextureCheckmarkOff;
				view.prime(textureSelectedOn, true);
				view.prime(textureSelectedOff, true);
				GridDrawables.sSelectedGrid.bindArrays(gl);
				for (int i = firstBufferedVisibleSlot; i <= lastBufferedVisibleSlot; ++i) {
					DisplayItem displayItem = displayItems[(i - firstBufferedVisibleSlot)
							* GridLayer.MAX_ITEMS_PER_SLOT];
					if (displayItem != null) {
						Texture textureToUse = selectedBucketList
								.find(displayItem.mItemRef) ? textureSelectedOn
								: textureSelectedOff;						
						drawDisplayItem(view, gl, displayItem, textureToUse,
								PASS_SELECTION_LABEL, null, 0);
					}
				}
				GridDrawables.sSelectedGrid.unbindArrays(gl);
			}
			GridDrawables.sVideoGrid.bindArrays(gl);
			Texture videoTexture = drawables.mTextureVideo;
			for (int i = firstBufferedVisibleSlot; i <= lastBufferedVisibleSlot; ++i) {
				DisplayItem displayItem = displayItems[(i - firstBufferedVisibleSlot)
						* GridLayer.MAX_ITEMS_PER_SLOT];
				if (displayItem != null && displayItem.mAlive) {
					if (displayItem.mItemRef.getMediaType() == MediaItem.MEDIA_TYPE_VIDEO) {
						drawDisplayItem(view, gl, displayItem, videoTexture,
								PASS_VIDEO_LABEL, null, 0);				
					}
				}
			}
			GridDrawables.sVideoGrid.unbindArrays(gl);
			gl.glDepthFunc(GL10.GL_LEQUAL);
		}
	}

	private void drawDisplayItem(RenderView view, GL11 gl,
			DisplayItem displayItem, Texture texture, int pass,
			Texture previousTexture, float mixRatio) {
		GridCamera camera = mCamera;
		Vector3f animatedPosition = displayItem.mAnimatedPosition;
		float translateXf = animatedPosition.x * camera.mOneByScale;
		float translateYf = animatedPosition.y * camera.mOneByScale;
		float translateZf = -animatedPosition.z;
		//MyLog.i("ydy2", "animatedPosition.x=="+animatedPosition.x+"  animatedPosition.y=="+animatedPosition.y+"  camera.mOneByScale=="+camera.mOneByScale);
		
		int stackId = displayItem.getStackIndex();
		final int maxDisplayedItemsPerSlot = (displayItem.mCurrentSlotIndex == mCurrentScaleSlot && mCurrentScaleSlot != Shared.INVALID) ? GridLayer.MAX_DISPLAYED_ITEMS_PER_FOCUSED_SLOT
				: GridLayer.MAX_DISPLAYED_ITEMS_PER_SLOT;
		if (pass == PASS_PLACEHOLDER || pass == PASS_FRAME_PLACEHOLDER) {
			translateZf = -0.04f;
		} else {
			if (pass == PASS_FRAME)
				translateZf += 0.02f;
			if ((pass == PASS_TEXT_LABEL || pass == PASS_LOCATION_LABEL || pass == PASS_SELECTION_LABEL)
					&& !displayItem.isAlive()) {
				translateZf = 0.0f;
			}
			if (pass == PASS_TEXT_LABEL && translateZf > 0) {
				translateZf = 0.0f;
			}
		}
		boolean usingMixedTextures = false;
		boolean bind = false;
		if ((pass != PASS_THUMBNAIL_CONTENT)
				|| (stackId < maxDisplayedItemsPerSlot && texture.isLoaded() && (previousTexture == null || previousTexture
						.isLoaded()))) {
			if (mixRatio == 1.0f || previousTexture == null
					|| texture == previousTexture) {
				bind = view.bind(texture);
			} else if (mixRatio != 0.0f) {
				if (!texture.isLoaded() || !previousTexture.isLoaded()) {
					// Submit the previous texture to the load queue
					view.bind(previousTexture);
					bind = view.bind(texture);
				} else {
					usingMixedTextures = true;
					bind = view.bindMixed(previousTexture, texture, mixRatio);
				}
			} else {
				bind = view.bind(previousTexture);
			}
		} else if (stackId >= maxDisplayedItemsPerSlot
				&& pass == PASS_THUMBNAIL_CONTENT) {
			mDisplayList.setAlive(displayItem, true);
		}
		if (!texture.isLoaded() || !bind) {
			if (pass == PASS_THUMBNAIL_CONTENT) {
				if (previousTexture != null && previousTexture.isLoaded()
						&& translateZf == 0.0f) {
					translateZf = -0.08f;
					bind |= view.bind(previousTexture);
				}
				if (!bind) {
					return;
				}
			} else {
				return;
			}
		} else {
			if (pass == PASS_THUMBNAIL_CONTENT || pass == PASS_FOCUS_CONTENT) {
				if (!displayItem.mAlive) {
					mDisplayList.setAlive(displayItem, true);
				}
			}
		}
		gl.glTranslatef(-translateXf, -translateYf, -translateZf);
		float theta = (pass == PASS_FOCUS_CONTENT) ? displayItem.mAnimatedImageTheta
				+ displayItem.mAnimatedTheta
				: displayItem.mAnimatedTheta;
		if (theta != 0.0f) {
			gl.glRotatef(theta, 0.0f, 0.0f, 1.0f);
		}
		float orientation = 0.0f;
		if (pass == PASS_THUMBNAIL_CONTENT
				&& displayItem.mAnimatedImageTheta != 0.0f) {
			orientation = displayItem.mAnimatedImageTheta;
		}
		if (pass == PASS_FRAME || pass == PASS_FRAME_PLACEHOLDER) {
			GridQuadFrame.draw(gl);
		} else {
			GridQuad.draw(gl, orientation);
		}
		if (theta != 0.0f) {
			gl.glRotatef(-theta, 0.0f, 0.0f, 1.0f);
		}
		gl.glTranslatef(translateXf, translateYf, translateZf);
		if (usingMixedTextures) {
			view.unbindMixed();
		}
	}
}
